﻿using Sunny.FrameDecoder;
using System;
using System.Net;

namespace Sunny.Tcp
{
    /// <summary>
    /// 帮助类
    /// </summary>
    public static class TcpHelper
    {
        internal static bool Exists(this byte[] data)
        {
            return data != null && data.Length > 0;
        }

        internal static bool NotExists(this byte[] data)
        {
            return data == null || data.Length == 0;
        }

        internal static bool ValidateTcpPort(this int port)
        {
            // on false, API should throw new ArgumentOutOfRangeException("port");
            return port >= IPEndPoint.MinPort && port <= IPEndPoint.MaxPort;
        }

        /// <summary>
        /// 字符串是否为IP地址
        /// </summary>
        /// <param name="ip">字符串</param>
        /// <returns>结果</returns>
        internal static bool IsIP4(this string ip)
        {
            string[] strs = ip.Split('.');
            if (strs.Length != 4)
            {
                return false;
            }

            foreach (string str in strs)
            {
                if (int.TryParse(str, out int value))
                {
                    if (value < 0) return false;
                    if (value > 255) return false;
                }
            }

            return true;
        }
    }

    public delegate void OnTcpClientConnectStateChanged(object sender, TcpClientEventArgs e);

    public class TcpClientEventArgs : EventArgs
    {
        public Sunny.Tcp.TcpClient Client { get; set; }


        public TcpClientEventArgs(Sunny.Tcp.TcpClient client)
        {
            Client = client;
        }
    }

    public delegate void OnTcpServerClientConnectStateChanged(object sender, TcpServerClientEventArgs e);

    public delegate void OnTcpServerClientDisconnectStateChanged(object sender, TcpServerClientDisconnectEventArgs e);

    public class TcpServerClientEventArgs : EventArgs
    {
        public TcpSocketClient Client { get; set; }

        public TcpClientConnectedType ConnectedType { get; set; }

        public TcpServerClientEventArgs(TcpSocketClient client, TcpClientConnectedType connectedType)
        {
            Client = client;
            ConnectedType = connectedType;
        }
    }

    public class TcpServerClientDisconnectEventArgs
    {
        public TcpSocketClient Client { get; set; }

        public TcpClientDisconnectedType DisconnectedType { get; set; }

        /// <summary>
        /// 是否为主动行为。
        /// </summary>
        public bool Manual { get; private set; }

        /// <summary>
        /// 消息
        /// </summary>
        public string Message { get; set; }

        public TcpServerClientDisconnectEventArgs(TcpSocketClient client, TcpClientDisconnectedType disconnectedType, bool manual, string message)
        {
            Client = client;
            DisconnectedType = disconnectedType;
            Manual = manual;
            Message = message;
        }
    }

    public enum TcpClientConnectedType
    {
        Connected,
        ConnectedByPing
    }

    public enum TcpClientDisconnectedType
    {
        Disconnected,
        DisconnectedByClient,
        DisconnectedByServer,
        DisconnectedByServerStopped,
        DisconnectedByPingTimeout,
        DisconnectedByFreeTimeout
    }

    /// <summary>
    /// 字节数组数据事件类
    /// </summary>
    /// <param name="sender">对象</param>
    /// <param name="e">字节数组数据事件类</param>
    public delegate void OnTcpClientByteEventHandler(object sender, TcpClientByteDataEventArgs e);

    /// <summary>
    /// Tcp字节数组解码数据事件类
    /// </summary>
    public class TcpClientByteDataEventArgs : EventArgs
    {
        /// <summary>
        /// 客户端
        /// </summary>
        public Sunny.Tcp.TcpClient Client { get; }

        /// <summary>
        /// 数据
        /// </summary>
        public IByteEventArgs Args { get; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="client">客户端</param>
        /// <param name="args">数据</param>
        public TcpClientByteDataEventArgs(Sunny.Tcp.TcpClient client, IByteEventArgs args)
        {
            Client = client;
            Args = args;
        }

        public TcpClientByteDataEventArgs(Sunny.Tcp.TcpClient client, byte[] value)
        {
            Client = client;
            Args = new ByteDataEventArgs(null, value);
        }

        public TcpClientByteDataEventArgs(Sunny.Tcp.TcpClient client, Span<byte> value)
        {
            Client = client;
            Args = new ByteDataEventArgs(null, value.ToArray());
        }
    }

    /// <summary>
    /// 字节数组数据事件类
    /// </summary>
    /// <param name="sender">对象</param>
    /// <param name="e">字节数组数据事件类</param>
    public delegate void OnTcpServerByteEventHandler(object sender, TcpServerByteDataEventArgs e);

    /// <summary>
    /// Tcp字节数组解码数据事件类
    /// </summary>
    public class TcpServerByteDataEventArgs
    {
        /// <summary>
        /// 服务端
        /// </summary>
        public TcpServer Server { get; set; }

        /// <summary>
        /// 客户端
        /// </summary>
        public TcpSocketClient Client { get; }

        /// <summary>
        /// 数据
        /// </summary>
        public IByteEventArgs Args { get; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="server">服务端</param>
        /// <param name="clientId">客户端编号</param>
        /// <param name="decoder">解码器</param>
        /// <param name="value">数据</param>
        public TcpServerByteDataEventArgs(TcpServer server, TcpSocketClient client, IByteEventArgs args)
        {
            Server = server;
            Client = client;
            Args = args;
        }

        public TcpServerByteDataEventArgs(TcpServer server, TcpSocketClient client, byte[] value)
        {
            Server = server;
            Client = client;
            Args = new ByteDataEventArgs(client.FrameDecoder, value);
        }

        public TcpServerByteDataEventArgs(TcpServer server, TcpSocketClient client, Span<byte> value)
        {
            Server = server;
            Client = client;
            Args = new ByteDataEventArgs(client.FrameDecoder, value.ToArray());
        }
    }

    public delegate void OnTcpSocketError(object sender, Exception e);
}
